using System;
using System.Collections.Generic;
using System.Text;
using BuildingBasicDomain;
using CommonTypes.Math;
using CommonTypes.Math.Geometry3D;
using BuildingStructuralElements;

using System.Collections;
using System.ComponentModel;
using System.Drawing;
using CommonTypes;

namespace BuildingStructuralElements
{
    public class CompositeStructural : StructuralElement,IEnumerable 
    {
        private List<StructuralElement> structurals = new List<StructuralElement>();

        public List<Section> Sections = new List<Section>();

        public Section FindSection(string name)
        {
            foreach (Section element in this.Sections )
                if (element.Name == name) return element;
            return null;
        }
       
        public CompositeStructural(string name)
        {
            Name = name;
        }

        public CompositeStructural()
        {
            Name = "Connection";
        }

        public override bool Move(Vector v)
        {
            foreach (StructuralElement element in this)
            {
                element.Move(v);
            }
            return true;
        }

        public override bool Move(double dx, double dy, double dz)
        {
            foreach (StructuralElement element in this)
            {
                element.Move(dx,dy,dz);
            }
            return true;
        }

        public override bool IsSelected
        {
            get
            {
                return true;
            }
            set
            {
                foreach (StructuralElement element in this)
                { element.IsSelected = value; }
            }
        }

        #region ICollection<StructuralElement> Members

        public void Add(StructuralElement item)
        {
            structurals.Add(item);
        }

        public void Clear()
        {
            structurals.Clear();
        }

        public bool Contains(StructuralElement item)
        {
            return structurals.Contains(item);
        }

        public void CopyTo(StructuralElement[] array, int arrayIndex)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public int Count
        {
            get {return  structurals.Count ; }
        }

        bool isReadOnly;
        public bool IsReadOnly
        {
            get { return isReadOnly; }
        }

        public bool Remove(StructuralElement item)
        {
            return structurals.Remove (item );
        }

        #endregion

        public StructuralElement Find(string name)
        {
            foreach (StructuralElement element in this)
                if (element.Name == name) return element;
            return null;
        }

        public void RotateToPoint(IPoint point, Vector3D angles)
        {
            foreach (StructuralElement element in this)
            {
                if (element is BeamElement)
                    ((BeamElement)element).RotateToPoint(point, angles);
                if (element is StructuralArea)
                    ((StructuralArea)element).RotateToPoint(point, angles);
            }
        }

        public void RotateToZero(Vector3D angles)
        {
            foreach (StructuralElement element in this)
            {
                if (element is BeamElement)
                    ((BeamElement)element).RotateToZero ( angles);
                if (element is StructuralArea)
                    ((StructuralArea)element).RotateToZero(angles);
            }
        }

        #region IEnumerable Members

        public IEnumerator GetEnumerator()
        {
            return structurals.GetEnumerator();
        }

        #endregion

        public override double AngleX
        {
            get
            {
                return base.AngleX;
            }
            set
            {
                this.RotateToZero( new Vector3D(value, 0, 0));
            }
        }

        public override double AngleY
        {
            get
            {
                return base.AngleY;
            }
            set
            {
                this.RotateToZero (new Vector3D(0, value, 0));
            }
        }

        public override double AngleZ
        {
            get
            {
                return base.AngleZ;
            }
            set
            {
                this.RotateToZero(new Vector3D(0, 0, value));
            }
        }

        public override double Dx
        {
            get
            {
                return base.Dx;
            }
            set
            {
                this.Move(new CommonTypes.Vector(value, 0, 0));
            }
        }

        public override double Dy
        {
            get
            {
                return base.Dy;
            }
            set
            {
                this.Move(new CommonTypes.Vector(0, value, 0));
            }
        }

        public override double Dz
        {
            get
            {
                return base.Dz;
            }
            set
            {
                this.Move(new CommonTypes.Vector(0, 0, value));
            }
        }
        public void Accept(MVCFramework .IVisitor  xmlVisitor)
        {
            xmlVisitor.Visit(this);
        }
    }

    public class BaseConnection : CompositeStructural
    {

        BeamElement column = BeamElement.CreateElement (new Node(0, 0, 0), new Node(0, 0.10, 0));

        BeamElement shearColumn = BeamElement.CreateElement  (new Node(0, 0, 0), new Node(0, -0.10, 0));
        GeneralPlate plate = new GeneralPlate();

        public double shearLength;
        public double pW;
        public double pH;
        public double pT;

        public double e1 = 0.010;
        public double e2 = 0.010;
        public int boltCount = 2;


        public double PlateWidth
        {
            get
            {
                return pW;
            }

            set
            {
                pW = value;
                BuildConnection();

            }


        }

        public double PlateHeigth
        {
            get
            {
                return pH;
            }

            set
            {
                pH = value;
                BuildConnection();

            }


        }


        public BeamElement MainColumn
        {
            get
            {
                return column;
            }

            set
            {
                column = value;
                BuildConnection();

            }


        }

        public BeamElement ShearColumn
        {
            get
            {
                return shearColumn;
            }

            set
            {
                shearColumn = value;
                BuildConnection();

            }


        }



        public BaseConnection(string name)
        {
            Name = name;

            shearLength = 1;

            pH = 0.2;
            pW = 0.2;
            pT = 0.3;
        }

        public BaseConnection()
        {
            Name = "BaseConnection";

            shearLength = 0.3;

            pH = 0.2;
            pW = 0.2;
            pT = 0.3;

    
        }


        public void BuildConnection()
        {
            Clear();
            plate.ClearPoints();

           // BuiltBolts();

           // BuiltColumn();

        //    BuiltShearColumn();

            BuiltPlate();

            BuiltStiffeners();

        }

        private void BuiltColumn()
        {

            column.AngleX = -90;

            column.Dy = column.Length () / 2 + pT / 2;
            Add(column);


        }

        private void BuiltShearColumn()
        {
            shearColumn.ElementColor = Color.Red;

            shearColumn.SNode.X = 0;
            shearColumn.SNode.Y = 0;
            shearColumn.SNode.Z = -shearLength / 2;

            shearColumn.ENode.X = 0;
            shearColumn.ENode.Y = 0;
            shearColumn.ENode.Z = shearLength / 2;


            shearColumn.AngleX = -90;
            shearColumn.Dy = -shearLength / 2 - pT / 2;
            Add(shearColumn);
        }

        private void BuiltPlate()
        {
            plate.T = pT;

            plate.AddOuterPoint(new Node(-pW / 2, 0, -pH / 2));
            plate.AddOuterPoint(new Node(pW / 2, 0, -pH / 2));
            plate.AddOuterPoint(new Node(pW / 2, 0, pH / 2));
            plate.AddOuterPoint(new Node(-pW / 2, 0, pH / 2));
            plate.AddOuterPoint(new Node(-pW / 2, 0, -pH / 2));

            Add(plate);
        }

        private void BuiltBolts()
        {
            Bolt b1 = new Bolt();
            b1.AngleX = 90;
            b1.Dx = pW / 2 - e1;
            b1.Dy = pT / 2;
            b1.BodyWidth = pT;

            Add(b1);

            Bolt b2 = new Bolt();
            b2.AngleX = 90;
            b2.Dy = pT / 2;
            b2.BodyWidth = pT;
            b2.Dx = -pW / 2 + e1;

            Add(b2);



        }
        private void BuiltStiffeners()
        {
            GeneralPlate p1 = new GeneralPlate();
            p1.T = ((SectionIRolled)column.Section).T;

            p1.AddOuterPoint(new Node(0, 0, 0));
            p1.AddOuterPoint(new Node(0, 0.100, 0));
            p1.AddOuterPoint(new Node(0.040, 0.100, 0));
            p1.AddOuterPoint(new Node(0.040, 0, 0));
            p1.AddOuterPoint(new Node(0, 0, 0));

            p1.Dz = ((SectionIRolled)column.Section).H / 2 - p1.T / 2;
            p1.Dx = ((SectionIRolled)column.Section).B / 2;


            Add(p1);

        }
    }

    public class CompositeBuilder
    {
        CompositeStructural composite = new CompositeStructural();
        
        # region  "Geometric atributes "
        private double dx, dy, dz;
        private double angleX, angleY, angleZ;

        [Description("Element Angle X Axis"), Category("Position")]
        public virtual double AngleX
        {
            set { angleX = value; }
            get { return angleX; }
        }

        [Description("Element Angle Y Axis"), Category("Position")]
        public virtual double AngleY
        {
            set { angleY = value; }
            get { return angleY; }
        }

        [Description("Element Angle Z Axis"), Category("Position")]
        public virtual double AngleZ
        {
            set { angleZ = value; }
            get { return angleZ; }
        }

        [Description("Displacement X"), Category("Position")]
        public virtual double Dx
        {
            set { dx = value; }
            get { return dx; }
        }

        [Description("Displacement Y"), Category("Position")]
        public virtual double Dy
        {
            set { dy = value; }
            get { return dy; }
        }

        [Description("Displacement Z"), Category("Position")]
        public virtual double Dz
        {
            set { dz = value; }
            get { return dz; }
        }
        # endregion  

        public void Rotate(double drx,double dry, double drz)
        {
            AngleX = AngleX + drx;
            AngleY = AngleY + dry;
            AngleZ = AngleZ + drz;
        }

        public void Move(double dx, double dy, double dz)
        {
            this.Dx = this.Dx + dx;
            this.Dy = this.Dy + dy;
            this.Dz = this.Dz + dz;
        }

        public void Add (StructuralElement element , double Rx,double Ry,
            double Rz, double Dx, double Dy, double Dz)
        {

        }

        public void PlaceBoltOnISection(SectionIRolled section, Bolt bolt)
        {

        }

    }


    #region Bolt

    public class Bolt : StructuralElement
    {
        private double bHeadDiameter;  //bolt diameter
        private double bHeadHeigth;  //bolt head height
        private double bBodyWidth;  //bolt body width
        private double bBodyDiameter;  //bolt body width

        #region Properties

        [Description("Diameter"), Category("Bolts")]
        public double HeadDiameter
        {
            get { return bHeadDiameter; }
            set
            {
                bHeadDiameter = value;
                needsUpdate = true;
            }

        }

        [Description("BoltHeadHeight"), Category("Bolts")]
        public double HeadHeight
        {
            get { return bHeadHeigth; }
            set
            {
                bHeadHeigth = value;
                needsUpdate = true;
            }

        }

        [Description("Diameter"), Category("Bolts")]
        public double BodyDiameter
        {
            get { return bBodyDiameter; }
            set
            {
                bBodyDiameter = value;
                needsUpdate = true;
            }

        }

        [Description("BoltBodyWidth"), Category("Bolts")]
        public double BodyWidth
        {
            get { return bBodyWidth; }
            set
            {
                bBodyWidth = value;
                needsUpdate = true;
            }

        }


        #endregion

        public Bolt()
        {
            ElementColor = Color.Brown;
            Alpha = 0.8;
            bHeadHeigth = 5;
            bHeadDiameter =5;
            bBodyWidth = 5;
            bBodyDiameter = 10;
            Name = "Bolt";
        }

        public Bolt(string name, int id, double headHeight, double headDiameter, double bodyWidth, double bodyDiameter, Color color)
        {
            ElementColor = color;
            bHeadHeigth = headHeight;
            bHeadDiameter = headDiameter;
            bBodyWidth = bodyWidth;
            bBodyDiameter = bodyDiameter;
            Name = name;
            Id = id;
        }
        private Node node;

        public Node Node
        {
            get { return node; }
            set { node = value; }
        }


        public Vector3D Direction;

        public override bool Move(Vector v)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public override bool Move(double dx, double dy, double dz)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public void Accept(MVCFramework .IVisitor  Visitor)
        {
            Visitor.Visit(this);
        }
    }

    #endregion

    #region GeneralPlate
   [Serializable ]
    public class GeneralPlate : StructuralElement
    {
        private ArrayList outerPoints = new ArrayList();
        [System.ComponentModel.Browsable(false)]
        protected virtual ArrayList OuterPoints
        {
            get { return outerPoints; }
            set { outerPoints = value; }
        }
        private ArrayList innerPoints = new ArrayList  () ;
        [System.ComponentModel.Browsable(false)]
        public ArrayList InnerPoints
        {
            get {
                /*if( innerPoints == null)
            {
                innerPoints = new ArrayList();
                    foreach (IPoint point in OuterPoints)
                    {
                        IPoint newpoint = new Node ( point .X /2, point .Y /2 ,point .Z /2);
                        innerPoints.Add(newpoint);
                    }
                }
            
                 **/ return innerPoints; 
               
            }
            set { innerPoints = value; }
        }
        private double t;  //plate thickness 
        private double maxY;

      
        private bool showEqRectPlate;
    
        private Color equalRectPlateColor;

        #region Properties

        [Description("Thickness"), Category("Geometry")]
        public double T
        {
            get { return t; }
            set
            {
                t = value;
                needsUpdate = true;
            }

        }


        [System.ComponentModel.Browsable(false)]
        public bool ShowEqualRectPlate
        {
            set { showEqRectPlate = value; }
            get { return showEqRectPlate; }
        }



        [System.ComponentModel.Browsable(false)]
        public Color EqualRectPlateColor
        {
            set { equalRectPlateColor = value; }
            get { return equalRectPlateColor; }
        }


        #endregion

        #region G,Q Loads
        private double q = 0;
        private double g = 0;


        [System.ComponentModel.Browsable(false)]
        public double Q
        {
            get { return q; }
            set
            {
                q = value;
            }

        }


        [System.ComponentModel.Browsable(false)]
        public double G
        {
            get { return g; }
            set
            {
                g = value;
            }

        }

        #endregion

        public GeneralPlate()
        {
            T = 0.1;
            maxY = 0.0f;

            Alpha = 0.8f;
            ElementColor = Color.LightSteelBlue ;
            Name = "General Plate";

            equalRectPlateColor = Color.White;
            showEqRectPlate = false;
        }

        public GeneralPlate(string name, int id, double T, Color color)
        {
            Name = name;
            t = T;
            ElementColor = color;
            Id = id;

            equalRectPlateColor = Color.White;
            showEqRectPlate = false;

        }


        public void AddOuterPoint(Node p)
        {
            OuterPoints.Add(p);
            needsUpdate = true;

            if (maxY < p.Y)
                maxY = p.Y;
        }

        public void AddInnerPoint(Node p)
        {
            InnerPoints.Add(p);
            needsUpdate = true;
        }


        public ArrayList GetOuterNodes()
        {
            return OuterPoints;
        }

        public ArrayList GetInnerNodes()
        {
            return InnerPoints;
        }


        public void GetPoints(out double[] x, out double[] y, out double[] z)
        {

            x = new double[OuterPoints.Count + InnerPoints.Count];
            y = new double[OuterPoints.Count + InnerPoints.Count];
            z = new double[OuterPoints.Count + InnerPoints.Count];


            for (int i = 0; i < OuterPoints.Count; i++)
            {
                Node p = (Node)(OuterPoints[i]);

                x[i] = p.X;
                y[i] = p.Y;
                z[i] = p.Z;

            }

            for (int i = 0; i < InnerPoints.Count; i++)
            {
                Node p = (Node)(InnerPoints[i]);
                x[i + OuterPoints.Count] = p.X;
                y[i + OuterPoints.Count] = p.Y;
                z[i + OuterPoints.Count] = p.Z;
            }

        }

        public int GetOuterPointsCount()
        {
            return OuterPoints.Count;

        }

        public int GetInnerPointsCount()
        {
            return InnerPoints.Count;

        }

        public void ClearPoints()
        {
            OuterPoints.Clear();
            InnerPoints.Clear();

            needsUpdate = true;
        }

        public void GetCircumscribedRectangle(out double xmin, out double xmax, out double ymin, out double ymax,         out double zmin, out double zmax)
        {

            Node p0 = (Node)(OuterPoints[0]);

            xmin = xmax = p0.X;
            ymin = ymax = p0.Y;
            zmin = zmax = p0.Z;

            for (int i = 0; i < OuterPoints.Count; i++)
            {
                Node p = (Node)(OuterPoints[i]);

                if (p.X < xmin)
                    xmin = p.X;
                if (p.X > xmax)
                    xmax = p.X;

                if (p.Y < ymin)
                    ymin = p.Y;
                if (p.Y > ymax)
                    ymax = p.Y;

                if (p.Z < zmin)
                    zmin = p.Z;
                if (p.Z > zmax)
                    zmax = p.Z;
            }

        }


        public static bool operator ==(GeneralPlate plate1, GeneralPlate plate2)
        {
            object o1 = plate1;
            object o2 = plate2;

            if (o1 == null && o2 == null) return true;
            if (o1 == null) return false;
            if (o2 == null) return false;


            foreach (Node n in plate1.GetOuterNodes())
            {
                if (!plate2.GetOuterNodes().Contains(n))
                    return false;
            }

            return true;
        }

        public static bool operator !=(GeneralPlate plate1, GeneralPlate plate2)
        {
            return !(plate1 == plate2);
        }

        public override bool Equals(object obj)
        {
            if (obj is GeneralPlate)
                return (bool)(this == (GeneralPlate)obj);
            else return false;
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }


        public void InitializeEqualPlate()
        {
            equalRectPlateColor = Color.White;


        }


        public override bool Move(Vector v)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public override bool Move(double dx, double dy, double dz)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public void Accept(MVCFramework .IVisitor  Visitor)
        {
            Visitor.Visit(this);
        }
    }
    #endregion


}
